Chapter 1:
Introduction

For the last few lessons, we've been concentrating on Java's GUI tools and how to use them to build an interactive application. While we haven't exhausted that topic by any means, there are some other topics I want to get to before we close out the course. We've gone over quite a few of the GUI classes, and the rest of them are similar enough that you'll be able to do a little digging and use them without too much trouble.

The topic we're going to dig into in this lesson is a group of Java's classes called collections. They're fundamental to a lot of programming, and you'll run into them frequently in real Java applications.

Java's collections are all designed to work with groups of data items. For example, if you think back to the team roster projects we did in Lessons 2 through 4, we used two of Java's collections there: arrays and ArrayLists. But there are several other types of collections, and we're going to look at a few of them in this lesson. Before we do, though, let's think about some of the data collections we use in everyday life. (We can forget about programming for a few minutes!)

We use various types of collections all the time. A to-do list, a calendar, and the phone numbers stored in our cell phones are all examples of collections. A collection is just an organized group of data. To-do lists and shopping lists organize things we need to do or buy. Our calendars organize our appointments and schedules. And our cell phones organize the phone numbers we want to save so we don't have to look them up in the phone book every time we want to call someone.

So it shouldn't be a surprise that one of the most common tasks in programming is working with groups of data items, and Java has some classes to help us do that.

Chapter 2:
Types of Collections

Before we get into the particulars of the classes, let's think about the different ways we organize our data. The reason there is more than one Java collection class is that there are several ways we organize data, and one class can't support them all. We often use these different organizations in our daily lives without stopping to recognize how they're different.

The simplest and perhaps most often used type of collection is a basic list. We use lists constantly: grocery lists, task lists, lists of pros and cons about decisions, and on and on. Lists are a part of our lives, like it or not. They're also often part of computer systems, where they take on some more specific characteristics.

Ordered collectionIn a computer system, we define a list as an ordered collection. When we use the term ordered here, we mean that each item has a position in the list, with one item in front of it (unless it's the first item) and one item behind it (unless it's the last item). In Java, we can retrieve a list's items from first to last, from last to first, or from a particular position in the list.

Sorted lists are another common form of lists. We often want to see list items in a certain order. For example, we might want to sort a task list by due date. Keeping a list sorted involves a certain amount of overhead, so we should only use them when necessary.

Queues and stacks are both more specialized forms of lists that we use often without thinking about it. If you've ever stood in line at an amusement park, a bank, or a grocery store, you have been in a queue. A queue has one added restriction that makes it different from a list: All new items are added at one end of the list and removed from the other end. It's a first-in, first-out list. We use that concept so often in computer systems that it has its own acronym: FIFO. Computer systems, especially shared or networked systems, use queues constantly. Every time we send an e-mail, it moves through a number of queues on the way to its destination.

Line of students at a classroom

Stack of platesStacks also differ from basic lists in one way: Instead of FIFO, stacks process items in LIFO order. As you might have guessed, that means last-in, first-out. To visualize a stack, think of a stack of plates. We normally add to the stack by putting plates on top, then take plates off the top when we need them. Computer systems use stacks to manage their resources, especially memory. You may not have realized it, but every time you call a method in a Java program, the computer uses a stack to manage your program's resources.

TQA-34 --- The last one I'll mention in detail is the map. A map also has some special properties that differentiate it from other collections. Phone bookAnd it's another structure that we use frequently—whenever we look up a telephone number, in fact. A map is a structure that contains two values for each entry: its key and its value. In a phone book (or in your cell phone), the key is the name of the person you want to call. The value is the phone number you get when you look up the name. Again, computer systems use maps often to store and retrieve information quickly when you have a key. It's much faster to find an entry when you can go straight to it rather than have to look through an entire list.

Java has a few more collections that are available if you ever need them, but they're not used as often, so I'll keep their descriptions very short.

Sets, priority queues, trees, and graphs are important in a number of technical applications, but we don't use them very often in early programming. So we won't talk about them anymore in this course. We'll concentrate on the collections that see more use in general-purpose programming.

Our approach to these collections will be to first create a simple application that uses a list and then see how using different collections changes the application. Our application will reuse some of the concepts we learned in working on our team roster projects back in Lessons 2 through 4, and we'll add some new capabilities to our repertoire as well.

The Lists Application

The first version of our application will present two views of our team roster, with each view using certain features of our list. The first view will display all the information about a single player, and we'll be able to move forward and backward through the list of players. That screen will look like this:

Team list Player View

Team list Player View

The second view will show a scrollable window with a text version of all players' information, something like this:

Team List Team View

Team List Team View

The File menu will have Open and Exit options. The Open menu item will allow us to choose a player file to open, and the Exit menu item will close the window.

The View menu will have Next and Previous options. The Next and Previous menu items will move us forward and backward in the list, updating the text fields in the Player View.

Between the two views, we will explore several of the capabilities of Java's list classes. Let's get started!

Chapter 3:
Setting Up

We'll need to borrow the Player class from the earlier lessons with a few very simple modifications. The modifications are nothing new, so I'm going to give you the updated Player class with several methods added to let us get individual fields out of Player objects. For example, I've added a getName() method to get the player's name, getPosition() to get the player's position, and other methods to get the values of each data field in the class. Remember to put this class file into the same directory or project that we'll use for our Lists class.

Our updated Player class

We'll also need a file of player information that we can use to populate our list. You can create your own if you like, but to make it easier I've included a text file you can copy and use below.

Our updated Player file

The last thing I'll give you to set up for this lesson is a program that will build the menus and open the window for us, since doing that is also review. That program is available at the link below, although if you're feeling ambitious, you can probably build it in about 15 minutes from earlier programs we've done.

Our beginning program

The above program will display the following window as a starting point for our application:

\Starting Lists Window

Starting Lists Window

Except for the Exit and About Lists menu items, none of the menu items functions yet. We will add their functions as we build the screen and the logic to produce our display.

Player View

We'll start with the layout of the Player View. It's a simple vertical sequence of alternating labels and text fields. We're going to need to be able to refer to them individually, though, when we update text values and when we switch views. The easiest way to do that is to make them instance variables so we can refer to them anywhere in our program. Let's add these labels and text fields at the top of our Lists class:

    // labels
private JLabel nameLabel;
private JLabel numLabel;
private JLabel positionLabel;
private JLabel avgPtsLabel;
private JLabel avgRbndsLabel;
private JLabel avgAssistsLabel;
	
    

// text fields private JTextField playerName; private JTextField playerNum; private JTextField playerPosition; private JTextField playerAvgPts; private JTextField playerAvgRbnds; private JTextField playerAvgAssists;

Now we're ready to flesh out our makeContent() method, which was completely empty in the code I gave you earlier in the chapter. Before we add components to it, though, we need to decide what layout manager to use. Since we have a simple vertical alignment, the BoxLayout manager with its vertical axis option (Y_AXIS) is the easiest and best choice. Let's add a line to set up that layout as the first line in makeContent():

    contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
    
    

One more thing before we start adding components: Remember how, in our pizza screen, the edges of the screen were right up against the components we added to it until we added a border to provide a little separation? We don't need a border with a line or a title this time, but let's add an empty border to our content pane, like we did to the pizza screen. After we get the design built and working, you can try your window without the border to see what it looks like if you want. You might even like it better that way! But for now, let's build it with the border so we have a little space around the edges. The border statement is the second line we'll add to makeContent():

    contentPane.setBorder(BorderFactory.createEmptyBorder(6,6,6,6));
    
    

Now we're finally ready to start adding our components. Let's add the first one together, then I'll let you add the other five on your own since they're very similar. The first thing to note about the labels and text fields in the example is that we don't want to use the standard font for them. We want bold, italicized text for the labels, and we want blue text for the fields. We also want the text to be slightly larger than the default font size. The example above uses a 14-point font rather than the default (usually 10 or 12 points). We can set up the first label and text field with the correct properties as follows:


    // player name
nameLabel = new JLabel("Player Name:");
nameLabel.setFont(new Font("Trebuchet MS",Font.BOLD + Font.ITALIC,14));
contentPane.add(nameLabel);
playerName = new JTextField();
playerName.setFont(new Font("Trebuchet MS",Font.PLAIN,14));
playerName.setForeground(Color.BLUE);
contentPane.add(playerName);
	
    

TQA-29 --- The first line creates a new JLabel object with the text for the first label, then assigns it to the nameLabel instance variable we created earlier. The second line shows us something new. It uses the JLabel object's setFont() method to change the default font settings for the label. That method, as you might expect, requires a Font object as its argument. The most common way to get a Font object is to simply create a new Font with the properties we want whenever we need one. And that's what we did here, although we could have named the Font object anything we wanted and used the name here just as well.

Creating a Font this way requires three arguments. The first is a font name. In this case, I just chose my personal favorite, but you can use any font you prefer. The second argument is a font style. The Font class itself includes three style options we can use here: Font.PLAIN, Font.BOLD, and Font.ITALIC. Their names are self-explanatory. To use both bold and italics at the same time, we just add them, as in the code above. The third argument is the size (in points) we want for our font. In this case, we used size 14.

The third line of code above adds the label to our content pane.

The next two lines create and set the font for our first text field in much the same way we just did for the label. The line after them, though, sets the foreground color for the text box, which is the color the text gets drawn in. We could also set the background fill color for the text box by using the JTextField method setBackground(). I'll let you experiment with that option if you'd like to.

The last line adds the text field to the content pane so we can see it in the window. If you've added this code to your makeContent() method, your program should create this window when it runs:

Window with the first field

Window with the first field

Go ahead and add the rest of the fields to the pane. When you're done, your program should generate a window that looks just like the first one in the lesson, except without any data in the fields. If you have trouble making it work, you can look at my makeContent() method here:

Our updated makeContent() method

Reading a File

Now that we've laid out the window, let's fill it in with some data. When we open a file, we want our program to read all the players into a list and then get the data for the first player in the list and display it in the Player View window. We'll want to save our position in the list, too, so we can move forward and backward to display other players in the window.

We'll do all that when we use the Open menu option to choose and open our input file, which means we'll use the inner listener class OpenMenuItemListener. Right now, all that class does is display a dialog box to acknowledge that the menu item was selected. Let's start by replacing that dialog display with the following code:

    JFileChooser fc = new JFileChooser();
fc.showOpenDialog(frame);
File playerFile = fc.getSelectedFile();
if (playerFile == null)
    return; 
    
    

This code introduces a new class that's very useful to us. The JFileChooser is Java's version of the File Open and File Save As dialogs in Windows, Mac OS X, and Linux. We'll use its Open dialog, which opens a window into the user's default directory, showing all the files and subdirectories it contains. The user can move around in the directory structure before selecting a file, and once he or she selects one, the JFileChooser object stores its file information so we can use it after the dialog closes.

The first line of the code above creates a new JFileChooser object named fc.

The next line calls its showOpenDialog() method to display the Open dialog box and allow the user to select the file to open. The argument to the method is the window that serves as the "parent" window to the dialog and to which control will return once the Open dialog closes. The dialog this call opens should look familiar:

Java File Open dialog

Java File Open dialog

The third line of code above takes the information gathered by the file chooser dialog and creates a File object with it. If the user didn't select a file but instead closed the window using the Cancel button, this file object will be null. That's why we included the next two lines, an if statement that ends the actionPerformed() method and leaves our Lists window unchanged if the user doesn't select a file. Without this if statement to end the method, trying to read data from the file would cause our program to crash if the user didn't select a file.

Assuming the user selects a valid text file with player information in a valid format, like the one I provided above, we won't use the if statement we just discussed, and we'll be ready to read the data from the file into our list. We did that once already back in Lesson 3, so I will just show you the code here, updated to reflect the results of using of the File Open dialog. We need to add code in three places. The first line we'll add is an import statement at the top of the file with the other import statements. We need to import java.io.*, since we will be using both the java.io.File and java.io.IOException classes.

    import java.io.*;
    
    

The next line we'll add will create our list variable as an instance variable in our program so we can use it in several of our methods. This line goes at the top of the class with the other instance variables:

    private ArrayList<Player> list;
    
    

Finally, we need to add the code below to the actionPerformed() method in OpenMenuItemListener:


    list = new ArrayList<Player>();
try
{
    Scanner scan = new Scanner(playerFile);
    while (scan.hasNext())
    {
        String name = scan.next() + " " + scan.next();
        int nbr = scan.nextInt();
        char position = scan.next().charAt(0);
        double avgPoints = scan.nextDouble();
        double avgRebounds = scan.nextDouble();
        double avgAssists = scan.nextDouble();
        list.add(new Player(name, nbr, position, avgPoints, avgRebounds, avgAssists));
    }
                
    scan.close();
}
catch(IOException e)
{
    JOptionPane.showMessageDialog(frame, 
            "I/O error in file\n\n     " +
                    playerFile.getName() +
                    "\n\nThis program will close", 
            "I/O Error", 
            JOptionPane.ERROR_MESSAGE);
    System.exit(1);
}
	
    

There is one other difference between this code and what we used in Lesson 3. This code displays an error dialog box if there is an I/O Error with the file instead of just sending an error message to the console. Then it closes the program.

But if the user selects a valid file, the code above creates an empty list, uses a Scanner object to open and read the file, loads each player's information into a Player object, and adds the Player object(s) to our list. When the program reaches the end of the file, it closes the Scanner object (and the file), and we have our Player objects in a list.

The next thing we need to do is load the first player's information from the list into the fields of the screen so we can see it. Then we'll save our position in the list so we can move forward and backward using the Next and Previous menu options. In order to do both of those, we're going to use a helper class that works with almost all Java collections—the Iterator class. Each Java collection that uses iterators can create an Iterator object that we can use to move through the collection.

The iterator provides us access to every element of the collection without duplicating any of them.

Chapter 4:
Iterators

Every Java Iterator has at least three capabilities:

  1. It can move forward through the list, getting us the next element in the collection.
  2. It can tell us if our collection has any more elements in the forward direction.
  3. It can delete elements from the collection without losing its place.

Java's lists have a ListIterator that can do two more things:

  1. It can tell us if there are any elements in the backward direction.
  2. In addition to moving forward, it can move backward through the list, getting us the previous list element.

We're going to use a ListIterator object to help us manage the list, track our current position, and get us the next or previous list element when we select those menu items. But first, let me show you visually how an iterator works. Assume we have a list with elements E1, E2 . . . En. When we get an iterator from the list, it points where the arrow below is. Iterators don't point at elements, they point between them.

Initial iterator position

Initial iterator position

This is the starting position of the iterator. As soon as we use the iterator's next() method to get the next element, it gives us back E1 and positions the iterator between E1 and E2, like this:

Iterator position after calling next()

Iterator position after calling next()

TQA-30 --- Another call to next() gets us element E2 and puts the iterator between E2 and E3. Wherever we are in the list, the iterator's hasNext() method will tell us whether there are more elements in front of our position. Once we have reached the end of the list, hasNext() tells us we can't go any further.

The iterator's hasPrevious() and previous() methods do exactly the same thing, only moving in the opposite direction. And if you think of how the iterators work, you can see that calling next() then calling previous() will get us the same element twice. (Remember that for the next lesson, when we learn how to move forward and backward through the list. We'll need that little fact to explain something.)

Now that we've seen how iterators work, let's look at how to code them. The first step is to import the class or interface we want to use. We're going to use ListIterator, so be sure to add an import statement at the top of your program for java.util.ListIterator (or java.util.*). Then, since we're going to want to use this iterator several places in our class to move through the list, we're going to add another instance variable at the top of our class, like this:

    private ListIterator<Player> lit;
    
    

Then we're going to add code to actionPerformed() again to initiate and use the Iterator object:

    lit = list.listIterator();
if (lit.hasNext())
{
    Player p = lit.next();
    getPlayer(p);
}
	
    

The first line of this code calls the ArrayList's listIterator() method to get a new iterator. The if statement in the next line checks to see if there are any elements in the list. If so, the third line uses the iterator's next() method to get the Player object, and the last line calls a helper method to put the player's information into the different fields in the window. I put this code into a helper method because we'll need it later on in our program. For now, here's the helper method, without comments since its purpose is pretty clear:

    private void getPlayer(Player p)
{
    playerName.setText(p.getName());
    playerNum.setText("" + p.getNum());
    playerPosition.setText(p.getPosition());
    playerAvgPts.setText("" + p.getAvgPoints());
    playerAvgRbnds.setText("" + p.getAvgRebounds());
    playerAvgAssists.setText("" + p.getAvgAssists());
}
	
    

If you've copied and saved the player data from above into a text file, you should now be able to run your program and have it display the empty Player View. Then if you use the File > Open . . . menu option, an Open dialog should let you open the text file you saved.

Your program should display information from the first player from the file in the window, like this:

First player's information

First player's information

Chapter 5:
Summary

We're making progress with our program. It can now open a player file, read its records into a list, and display the first player on the screen. That's quite a lot!

We still want to move through the player list in the Player View, we have another view to build, and we want to be able to alternate between the views. But that's more than we can accomplish in one lesson, so we'll leave that part of the project, as well as the discussion of how to use other collection types, for next time.

I'll see you then.


Lesson 10 FAQs

Q: Iterators seem complicated. Isn't there an easier way to traverse a collection in Java?

A: As we saw in an earlier lesson, and will see again in a future one, there is another way to traverse a collection and process every element in it. The way to do it is with the for-each loop, which retrieves each collection element once for us in one simple statement.

The for-each loop has some disadvantages, though. You cannot delete elements from the collection in a for-each loop because that makes it unpredictable, but you can use an iterator to add or delete elements. A for-each loop also will not allow you to remember its position in the collection while you wait for a user. The for-each loop simply runs through the collection from start to finish; it can't stop its retrieval and then pick it up again later.

Lesson 10 Assignment


For this lesson's assignment, take the finished program from the lesson and add one more item to it. Add another data field to the window and to each player for the player's average minutes played per game.

Besides adding the label and text box to the window, you will need to add the field to the player class, update its constructor, and provide a get() method so the value can be retrieved. Last, you will need to update the data file with a data value for each player's minutes played.

Let me know if you have any questions about the assignment.

Lesson 10 Quiz Answers

1. Which of the following statements will set the color of the text in a GUI text field named tf to red?
tf.setForeground(Color.RED);

2. Which of the following statements will put a text string into a text field named tf?
tf.setText("Text to copy");

3. If we have an iterator named it, which of the following calls will tell us whether there are more elements in the list?
it.hasNext()

4. What is the purpose of an iterator?
To traverse a collection and retrieve its elements one at a time.

5. What is the difference between a stack and a queue?
A stack is a last-in-first-out (LIFO) collection, and a queue is a first-in-first-out (FIFO) collection.


Lesson 10 Supplementary Materials